package it.giuseppetrisciuoglio.lyrics.processor;

import it.giuseppetrisciuoglio.lyrics.adapter.ArtistaCanzone;
import it.giuseppetrisciuoglio.lyrics.exception.LyricsException;
import it.giuseppetrisciuoglio.lyrics.exception.LyricsNotFoundException;
import it.giuseppetrisciuoglio.lyrics.http.HttpReader;
import it.giuseppetrisciuoglio.lyrics.manager.JMSManager;
import it.giuseppetrisciuoglio.lyrics.parser.AbstractTestoParser;
import it.giuseppetrisciuoglio.lyrics.persistence.entity.Canzone;
import it.giuseppetrisciuoglio.lyrics.persistence.entity.Errore;
import it.giuseppetrisciuoglio.lyrics.persistence.entity.ParserType;
import it.giuseppetrisciuoglio.lyrics.persistence.entity.Transaction;
import it.giuseppetrisciuoglio.lyrics.persistence.repository.CanzoneRepository;
import it.giuseppetrisciuoglio.lyrics.persistence.repository.TransactionRepository;
import it.giuseppetrisciuoglio.lyrics.utils.StringUtilies;

import java.io.IOException;

import org.apache.camel.Exchange;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.HttpResponseException;
import org.htmlparser.util.ParserException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

public class AbstractProcessor {

	private final transient Logger log = LoggerFactory.getLogger(getClass());
	
	@Autowired
	private HttpReader httpReader;
	
	@Autowired
	private CanzoneRepository canzoneRepository;

	@Autowired
	private JMSManager jmsManager;
	
	@Autowired
	private TransactionRepository transactionRepository;
	
	public void process(Exchange exchange, ParserType parserType) throws LyricsException {
		log.debug("process(): exchange={}", exchange, parserType);
		ArtistaCanzone artistaCanzone = (ArtistaCanzone) exchange.getIn().getBody();
		if (artistaCanzone != null){
			String testo = null;
			String url = null;
			String response = null;
			try {
				
				AbstractTestoParser parser = AbstractTestoParser.getAbstractTestoParser(parserType);
				url = parser.getURL(artistaCanzone.getNomeArtista(), artistaCanzone.getTitoloCanzone());
				
				log.debug("process(): url={}", url);
				response = httpReader.getResponse(url);
				
				log.debug("process(): response={}", StringUtils.abbreviate(response, 255));
				if (response == null){
					throw new LyricsNotFoundException();
				}
				
				testo = parser.getTesto(response);
				
				Canzone canzone = canzoneRepository.findOne(artistaCanzone.getCanzoneId());
				canzone.setTesto(testo);
				canzoneRepository.save(canzone);
				
			} catch (LyricsNotFoundException e) {
				log.debug("process(): retry, LyricsNotFoundException={}", e.getMessage());
				saveTransaction(artistaCanzone.getTransactionId(), parserType);
				manageException(artistaCanzone, url, e, response);
				manageRetry(artistaCanzone);
			} catch (ParserException e) {
				log.debug("process(): retry, ParserException={}", e.getMessage());
				saveTransaction(artistaCanzone.getTransactionId(), parserType);
				manageException(artistaCanzone, url, e);
				manageRetry(artistaCanzone);
			} catch (HttpResponseException e) {
				log.debug("process(): retry, HttpResponseException={}", e.getMessage());
				saveTransaction(artistaCanzone.getTransactionId(), parserType);
				manageException(artistaCanzone, url, e);
				if (e.getStatusCode() == 403){
					log.debug("process(): not retry, stop processor.", e.getMessage());
					throw new LyricsException();
				}
				manageRetry(artistaCanzone);
			} catch (IOException e) {
				log.debug("process(): retry, IOException={}", e.getMessage());
				manageException(artistaCanzone, url, e);
				manageRetry(artistaCanzone);
			} catch (Exception e) {
				log.debug("process(): not retry, exception={}", e.getMessage());
				saveTransaction(artistaCanzone.getTransactionId(), parserType);
				manageException(artistaCanzone, url, e);
			}
		}
	}
	
	private void saveTransaction(String transactionId, ParserType parserType){
		Transaction transaction = new Transaction();
		transaction.setCode(transactionId);
		transaction.setParserType(parserType);
		transactionRepository.save(transaction);
	}
	
	private void manageException(ArtistaCanzone artistaCanzone, String url, Exception e, String response){
		log.debug("manageException(): artistaCanzone={}, url={}", artistaCanzone, url);
		Errore errore = new Errore();
		errore.setArtistaId(artistaCanzone.getArtistaId());
		errore.setCanzoneId(artistaCanzone.getCanzoneId());
		errore.setTransactionCode(artistaCanzone.getTransactionId());
		errore.setError(e.getMessage());
		errore.setErrorTrace(StringUtilies.getStackTrace(e));
		errore.setUrl(url);
		errore.setResponse(response);
		jmsManager.sendError(errore);
		log.debug("manageException(): exit, return.");
	}
	
	private void manageException(ArtistaCanzone artistaCanzone, String url, Exception e){
		manageException(artistaCanzone, url, e, null);
	}
	
	private void manageRetry(ArtistaCanzone artistaCanzone){
		log.debug("manageException(): artistaCanzone={}", artistaCanzone);
		jmsManager.sendRetry(artistaCanzone);
		log.debug("manageException(): exit, return.");
	}
}
